package com.personal.gateway.flinkAllCommand.configurationOption;

import com.personal.gateway.flinkAllCommand.configurationOption.configurationGenerator.AbstractConfigurationGenerator;
import com.personal.gateway.flinkAllCommand.configurationOption.configurationType.*;
import com.personal.gateway.flinkAllCommand.configurationOption.parameterCheck.AbstractParameterCheck;
import com.personal.gateway.flinkAllCommand.configurationOption.webObjectGenerator.AbstractWebObjectGenerator;

import java.util.List;
import java.util.Map;

/**
 * @author BigHead
 * @date 2022/1/10 16:35
 * @description ConfigurationOptionBuilder
 */
public class ConfigurationOptionBuilder {
    /**
     * 组别
     */
    private final KeyIndexInfomationDao groupKey;
    /**
     * 配置文件key
     */
    private final KeyIndexInfomationDao configurationKey;
    /**
     * 页面配置展示名称
     */
    private String webShowName;
    /**
     * 字段描述
     */
    private String describe;
    /**
     * 是否必传
     */
    private boolean necessary;
    /**
     * 前提条件
     */
    private ConfigurationOption<?, ?> antecedentConfigurationOption;
    /**
     * 是否存在带组装参数
     */
    private boolean hasChildConfigurations;

    ConfigurationOptionBuilder(
            KeyIndexInfomationDao groupKey,
            KeyIndexInfomationDao configurationKey
    ) {
        this.groupKey = groupKey;
        this.configurationKey = configurationKey;
        this.webShowName = configurationKey.getName();

        this.describe = "";
        this.necessary = true;
        this.hasChildConfigurations = false;
    }

    public static ConfigurationOptionBuilder startBuilder(
            KeyIndexInfomationDao groupKey,
            KeyIndexInfomationDao configurationKey
    ) {
        return new ConfigurationOptionBuilder(groupKey, configurationKey);
    }

    public ConfigurationOptionBuilder webShowName(String webShowName) {
        this.webShowName = webShowName;
        return this;
    }

    public ConfigurationOptionBuilder describe(String describe) {
        this.describe = describe;
        return this;
    }

    public ConfigurationOptionBuilder necessary(boolean necessary) {
        this.necessary = necessary;
        return this;
    }

    public ConfigurationOptionBuilder antecedentConfigurationOption(ConfigurationOption<?, ?> antecedentConfigurationOption) {
        this.antecedentConfigurationOption = antecedentConfigurationOption;
        return this;
    }

    /**
     * 类型生成器
     */

    public ConfigurationTypeBuilder<AbstractConfigurationTypeClass, ConfigurationTypeClass> typeClass(
            Class<AbstractConfigurationTypeClass> configurationType
    ) {
        this.hasChildConfigurations = true;
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeClass(configurationType)
        );
    }

    public ConfigurationTypeBuilder<Double, ConfigurationTypeDouble> typeDouble() {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeDouble()
        );
    }

    public ConfigurationTypeBuilder<Enum<? extends ConfigurationTypeEnumInterface>, ConfigurationTypeEnum> typeEnum(
            Class<Enum<? extends ConfigurationTypeEnumInterface>> configurationType
    ) {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeEnum(configurationType)
        );
    }

    public ConfigurationTypeBuilder<Integer, ConfigurationTypeInteger> typeInteger() {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeInteger()
        );
    }

    public ConfigurationTypeBuilder<List<Map<String, String>>, ConfigurationTypeListMap> typeListMap() {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeListMap()
        );
    }

    public ConfigurationTypeBuilder<List<String>, ConfigurationTypeListString> typeListString() {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeListString()
        );
    }

    public ConfigurationTypeBuilder<String, ConfigurationTypeString> typeString() {
        return new ConfigurationTypeBuilder<>(
                this,
                new ConfigurationTypeString()
        );
    }

    public static class ConfigurationTypeBuilder<BT, CT extends AbstractConfigurationType<BT>> {

        private final ConfigurationOptionBuilder configurationOptionBuilder;
        private final CT configurationType;

        ConfigurationTypeBuilder(
                ConfigurationOptionBuilder configurationOptionBuilder,
                CT configurationType
        ) {
            this.configurationOptionBuilder = configurationOptionBuilder;
            this.configurationType = configurationType;
        }

        @SafeVarargs
        public final ConfigurationTypeBuilder<BT, CT> setExampleValue(BT... exampleValue) {
            configurationType.setExampleValue(exampleValue);
            return this;
        }

        public final ConfigurationTypeBuilder<BT, CT> setMinMaxValue(BT minValue, BT maxValue) {
            configurationType.setMinMaxValue(minValue, maxValue);
            return this;
        }

        public WebObjectGeneratorBuilder<BT, CT> webObjectGenerator(Class<? extends AbstractWebObjectGenerator<BT, CT>> webObjectGenerator) {
            return new WebObjectGeneratorBuilder<BT, CT>(
                    this,
                    webObjectGenerator
            );
        }

    }

    public static class WebObjectGeneratorBuilder<BT, CT extends AbstractConfigurationType<BT>> {

        private final ConfigurationOptionBuilder configurationOptionBuilder;
        private final CT configurationType;
        private final Class<? extends AbstractWebObjectGenerator<BT, CT>> webObjectGenerator;

        WebObjectGeneratorBuilder(
                ConfigurationTypeBuilder<BT, CT> configurationTypeBuilder,
                Class<? extends AbstractWebObjectGenerator<BT, CT>> webObjectGenerator
        ) {
            this.configurationOptionBuilder = configurationTypeBuilder.configurationOptionBuilder;
            this.configurationType = configurationTypeBuilder.configurationType;
            this.webObjectGenerator = webObjectGenerator;
        }

        public ParameterCheckBuilder<BT, CT> parameterCheck(Class<? extends AbstractParameterCheck<BT, CT>> parameterCheck) {
            return new ParameterCheckBuilder<>(
                    this,
                    parameterCheck
            );
        }

    }

    public static class ParameterCheckBuilder<BT, CT extends AbstractConfigurationType<BT>> {
        private final ConfigurationOptionBuilder configurationOptionBuilder;
        private final CT configurationType;
        private final Class<? extends AbstractWebObjectGenerator<BT, CT>> webObjectGenerator;
        private final Class<? extends AbstractParameterCheck<BT, CT>> parameterCheck;

        ParameterCheckBuilder(
                WebObjectGeneratorBuilder<BT, CT> webObjectGeneratorBuilder,
                Class<? extends AbstractParameterCheck<BT, CT>> parameterCheck
        ) {
            this.configurationOptionBuilder = webObjectGeneratorBuilder.configurationOptionBuilder;
            this.configurationType = webObjectGeneratorBuilder.configurationType;
            this.webObjectGenerator = webObjectGeneratorBuilder.webObjectGenerator;
            this.parameterCheck = parameterCheck;
        }

        public ConfigurationGeneratorBuilder<BT, CT> configurationGenerator(Class<? extends AbstractConfigurationGenerator<BT, CT>> configurationGenerator) {
            return new ConfigurationGeneratorBuilder<>(
                    this,
                    configurationGenerator
            );
        }
    }

    public static class ConfigurationGeneratorBuilder<BT, CT extends AbstractConfigurationType<BT>> {
        private final ConfigurationOptionBuilder configurationOptionBuilder;
        private final CT configurationType;
        private final Class<? extends AbstractWebObjectGenerator<BT, CT>> webObjectGenerator;
        private final Class<? extends AbstractParameterCheck<BT, CT>> parameterCheck;
        private final Class<? extends AbstractConfigurationGenerator<BT, CT>> configurationGenerator;

        ConfigurationGeneratorBuilder(
                ParameterCheckBuilder<BT, CT> parameterCheckBuilder,
                Class<? extends AbstractConfigurationGenerator<BT, CT>> configurationGenerator
        ) {
            this.configurationOptionBuilder = parameterCheckBuilder.configurationOptionBuilder;
            this.configurationType = parameterCheckBuilder.configurationType;
            this.webObjectGenerator = parameterCheckBuilder.webObjectGenerator;
            this.parameterCheck = parameterCheckBuilder.parameterCheck;
            this.configurationGenerator = configurationGenerator;
        }

        public ConfigurationOption<BT, CT> build() {
            return new ConfigurationOption<>(
                    this.configurationOptionBuilder.groupKey,
                    this.configurationOptionBuilder.configurationKey,
                    this.configurationOptionBuilder.webShowName,
                    this.configurationOptionBuilder.describe,
                    this.configurationOptionBuilder.necessary,
                    this.configurationType,
                    this.webObjectGenerator,
                    this.parameterCheck,
                    this.configurationGenerator,
                    this.configurationOptionBuilder.antecedentConfigurationOption,
                    this.configurationOptionBuilder.hasChildConfigurations
            );
        }
    }
}
